/**
*    Copyright (C) 2008  Chase Kernan 
*    chase.kernan@gmail.com
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
* 
**/

package com.chasekernan.hxnova.server;

import com.chasekernan.hxnova.core.players.Player;
import com.chasekernan.hxnova.core.minerals.MineralSet;
import com.chasekernan.hxnova.core.fleets.Fleet;
import com.chasekernan.hxnova.utils.Vector;
import com.chasekernan.hxnova.core.dataholders.FleetHolder;
import com.chasekernan.hxnova.core.dataholders.Global;

/**
    Contains static methods to handle changing fleets around as a "waypoint 0" 
    order.
**/
class FleetManipulations {
    
    /**
        Checks to make sure that the player hasn't cheated when moving around
        their fleets.
        
        This will throw an error if anything weird happens or if it's passed a
        null value.
    **/
    public static function check(player : Player, location : Vector, 
                                 newFleets : Array<Fleet>) {
        var oldFleets = Global.fleets.getParticlesAtLocation(location, player);
        
        var oldIds = new Array<Int>();
        var oldFuel = 0.0;
        var oldColonists = 0;
        var oldMinerals = new MineralSet();
        var totalStacks = new Array<ShipStack>();
        
        for (fleet in oldFleets) {
            oldIds.push(fleet.id);
            oldFuel += fleet.fuel;
            oldColonists += fleet.colonists;
            oldMinerals.add(fleet.minerals);
            
            for (stack in fleet.ships) {
                var found = false;
                for (match in totalStacks) {
                    if (stack.type == match.type) {
                        match.amount += stack.amount;
                        match.armor += stack.armor;
                        match.shields += stack.shields;
                        found = true;
                        break;
                    }
                }
                
                if (!found) {
                    totalStacks.push(stack);
                }
            }
        }
        
        for (fleet in newFleets) {
            //this also checks for correct values
            if (!fleet.checkForCompleteServerInfo()) {
                throw "The complete info for the new fleet needs to be " + 
                      "provided (correctly).";
            }
            
            if (fleet.owner.id != player.id) {
                throw "The fleet being manipulated isn't owned by the player.";
            }
            
            oldFuel -= fleet.fuel;
            oldColonists -= fleet.colonists;
            oldMinerals.subtract(fleet.minerals);
            
            for (stack in fleet.ships) {
                var found = false;
                for (match in totalStacks) {
                    if (stack.type == match.type) {
                        match.amount -= stack.amount;
                        match.armor -= stack.armor;
                        match.shields -= stack.shields;
                        found = true;
                        break;
                    }
                }
                
                if (!found) {
                    throw "Player #" + player.id + " tried to add a " + 
                          "non-existant stack type.";
                }
            }
            
            //ids
            var found = false;
            for (id in oldIds) {
                if (fleet.id == id) {
                    oldIds.remove(id);
                    found = true;
                    break;
                }
            }
            
            if (found) continue;
            
            //if it hasn't been found yet, see if that id corresponds to an 
            //empty id slot.
            if (Global.fleets.getById(fleet.id, player.id) != null) {
                throw "The newly assigned id is already used by another fleet.";
            }
        }
        
        if (Math.abs(oldFuel) > 0.01) {
            throw "Fuel doesn't match up after fleet manipulations.";
        } else if (oldColonists != 0) {
            throw "Colonists don't match up after fleet manipulations.";
        } else if (oldMinerals.getMass() != 0) {
            throw "Minerals don't match up after fleet manipulations.";
        } 
        
        for (stack in totalStacks) {
            if (stack.amount != 0 || stack.armor != 0 || stack.shields != 0) {
                throw "Stacks don't match up after fleet manipulations.";
            }
        }
    }
    
    public static function apply(player : Player, location : Vector, 
                                 newFleets : Array<Fleet>) {
        var oldFleets = Global.fleets.getParticlesAtLocation(location, player);
        
        for (fleet in oldFleets) Global.fleets.removeParticle(fleet);
        for (fleet in newFleets) Global.fleets.addParticle(fleet);
    }
}